package com.dhweb.core;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.util.ZipUtil;
import com.dhweb.constants.CompressConstants;
import com.dhweb.entity.AppCompressInfo;
import com.dhweb.entity.AppMsg;
import com.dhweb.entity.CompressConfig;
import com.dhweb.util.CompressUtil;

import java.io.File;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import static com.dhweb.constants.CompressStepEnum.*;

/**
 * @author zhouxl
 * @DATE 2021/8/24
 * @descriptoin
 */
public class AppCompressService {

    public void run(CompressConfig config){
        List<AppCompressInfo> apps = scanPackage(config);
        apps = extractZip(apps, config);
    }

    /**
     * 扫描包，生成@see AppComressInfo信息
     * @return
     */
    public List<AppCompressInfo> scanPackage(CompressConfig config){
        List<AppCompressInfo> apps = new ArrayList<>();
        findZip(new File(config.getScanPackage()),apps);
        return apps;
    }

    /** 抽取 extract */
    public List<AppCompressInfo> extractZip(List<AppCompressInfo> apps, CompressConfig config) {
        /*
            1.解压zip文件，到指定的目录
            2.找到index页面信息
            3.压缩 index页面的目录
         */
        if( apps == null ){
            return apps;
        }
        for(AppCompressInfo app : apps ){
            decompressionZip(app,config);
            findIndexPage(app,config);
            compressIndexDir(app,config);
            cleanTempFile(app,config);
        }
        return apps;
    }

    /** 解压 */
    public void decompressionZip(AppCompressInfo app, CompressConfig config){
        String rootDir = config.getCompressDir() == null ? config.getScanPackage() : config.getCompressDir();
        String decompressDirPath = rootDir + File.separator + CompressConstants.TRANSFER_DIR_NAME;
        // 检查当前zip包是否存了
        String sourceZipPath = app.getSourceZipPath();
        File sourceZip = new File(sourceZipPath);
        String zipFileName = sourceZip.getName();

        String uploadDir = rootDir + File.separator + CompressConstants.UPLOAD_DIR_NAME + File.separator + zipFileName;
        if( new File(uploadDir).exists() ){
            AppMsg msg = new AppMsg("扫描的zip包存在重名现象，源zip包路径地址："+app.getSourceZipPath());
            app.getAppMsgList().add(msg);
        }
        File decompressDir = new File(decompressDirPath);
        if( !decompressDir.exists() ){
            decompressDir.mkdirs();
        }
        decompressDirPath = decompressDirPath + File.separator + app.getNoSuffixFileName();
        // todo 这里需要搞一个策略模式，如果utf-8编码解压出现问题，那么换成gbk，如果不想再换成其他的
        boolean success = unzip(app, decompressDirPath);
        app.setError(success?0:1);
        app.setStep(DecompressionZip.getStep());
        app.setStepDesc(DecompressionZip.getStepDesc());
    }

    /** 找到index页面信息 */
    public void findIndexPage(AppCompressInfo app, CompressConfig config){
        if( app.getError() == 1 ){
            return ;
        }
        String decompressZipPath = app.getDecompressZipPath();
        File decompressDir = new File(decompressZipPath);
        if( !decompressDir.exists() ){
            AppMsg msg = new AppMsg("源zip="+app.getSourceZipPath()+"解压后的解压文件夹遗失了,遗失的文件夹="+decompressZipPath);
            app.getAppMsgList().add(msg);
            return ;
        }

        String indexPagePath = toFindIndexPage(new File(decompressZipPath));
        if( indexPagePath == null ){
            app.setError(1);
            AppMsg appMsg = new AppMsg("源zip文件结构不合法，源zip文件地址="+app.getSourceZipPath());
            app.getAppMsgList().add(appMsg);
        }
        app.setStep(FindIndexPage.getStep());
        app.setStepDesc(FindIndexPage.getStepDesc());
        app.setIndexPagePath(indexPagePath);
    }

    /**
     * 找目录下index.html处理逻辑
     * @param decompressDir
     * @return
     */
    public String toFindIndexPage(File decompressDir){
        if( decompressDir.isDirectory()){
            File[] files = decompressDir.listFiles();
            boolean flag = false;
            int index = 0;
            for(File f: files ){
                if( f.isFile() && "index.html".equals(f.getName().toLowerCase())){
                    flag = true;
                    break;
                }
                index ++;
            }
            if( flag ){
                /** 这里做一个检验 index.html + css + js */
                boolean check = CompressUtil.checkZipFileLegitimate(files);
                return check ? files[index].getAbsolutePath():null;
            }
            for(File f : files ){
                if( f.isDirectory() ){
                    return toFindIndexPage(f);
                }
            }
        }
        return null;
    }

    /** 压缩 index页面的目录 */
    public void compressIndexDir(AppCompressInfo app, CompressConfig config){
        if( app.getError() == 1 ){
            return ;
        }
        String indexPagePath = app.getIndexPagePath();
        File indexParentDir = new File(indexPagePath);
        if( !indexParentDir.exists() ){
            return ;
        }
        // 上传的目录文件
        String uploadDir = config.getCompressDir() + File.separator + CompressConstants.UPLOAD_DIR_NAME;
        File uploadFileDir = new File(uploadDir);
        if( !uploadFileDir.exists()){
            uploadFileDir.mkdirs();
        }
        File waitForCompressFile = new File(app.getIndexPagePath()).getParentFile();
        String uploadZipDir = uploadDir + File.separator + app.getNoSuffixFileName() +
                File.separator + waitForCompressFile.getName() + ".zip";
        try{
            File zip = ZipUtil.zip(waitForCompressFile.getAbsolutePath(), uploadZipDir,true);
            app.setUploadZipPath(zip.getAbsolutePath());
        }catch (Exception ex){
            app.setError(1);
            AppMsg appMsg = new AppMsg("解压index文件失败,文件路径地址:"+waitForCompressFile);
            app.getAppMsgList().add(appMsg);
        }
        app.setStep(CompressIndexDir.getStep());
        app.setStepDesc(CompressIndexDir.getStepDesc());
    }

    /** 清理临时文件 */
    public void cleanTempFile(AppCompressInfo app, CompressConfig config){
        // 保留解压失败的临时文件记录
        if( app.getError() == 1 ){
            return ;
        }
        String decompressZipPath = app.getDecompressZipPath();
        File decompressFile = new File(decompressZipPath);
        if( decompressFile.exists() ){
            FileUtil.del(decompressFile);
        }
        app.setStep(CleanTempFile.getStep());
        app.setStepDesc(CleanTempFile.getStepDesc());
    }

    /**
     * 便利目录找到zip文件
     * @param parent
     * @return
     */
    public void findZip(File parent, List<AppCompressInfo> apps){
        if( parent.isDirectory() ){
            File[] files = parent.listFiles();
            for(File f : files ){
                findZip(f,apps);
            }
        }else {
            String fileName = parent.getName();
            String fileType = CompressUtil.getFileSuffixToLower(fileName);
            if( CompressUtil.compressFileType(fileType)){
                String noSuffixFileName = CompressUtil.getFileNameNoSuffix(parent);
                AppCompressInfo app = new AppCompressInfo();
                app.setCompressType(fileType);
                app.setNoSuffixFileName(noSuffixFileName);
                app.setSourceZipPath(parent.getAbsolutePath());
                app.setStep(ScanZipPackage.getStep());
                app.setStepDesc(ScanZipPackage.getStepDesc());
                apps.add(app);
            }
        }
    }

    /**
     * 这里想想如何采用策略模式，进行处理
     * @param app
     * @param decompressDirPath
     */
    public boolean unzip(AppCompressInfo app,String decompressDirPath){
        int flag = 0;
        int index = 0;
        for(index=0; index<CompressConstants.COMPRESS_CHARSET.size(); index++){
            try{
                Charset charset = Charset.forName(CompressConstants.COMPRESS_CHARSET.get(index));
                ZipUtil.unzip(app.getSourceZipPath(), decompressDirPath,charset);
                app.setDecompressZipPath(decompressDirPath);
                flag = 0;
            }catch (IllegalArgumentException ex){
                flag = 1;
            }catch (IORuntimeException ex){
                flag = 2;
            }catch (Exception ex){
                flag = 3;
            }
            if( flag != 1){
                break;
            }else{
                // 删除已经创建好的文件信息
                File decompressDir = new File(decompressDirPath);
                if( decompressDir.exists() ){
                    FileUtil.del(decompressDir);
                }
            }
        }
        return flag == 0;
    }
}
